#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/gpio.h>

#define DEVICE_NAME     "car_sensor"

#ifndef assert
#define assert(isTrue) if(!(isTrue)) \
	printk("something wrong in file : %s line : %d\n", __FILE__, __LINE__); \
			if(!(isTrue)) \
			while(1)

#endif

typedef struct SensorState
{
	int id;
	int state;
	unsigned long tick;
}SensorState;

static struct fasync_struct *async_queue = NULL; 

#define STATE_CACHE_CNT 4096 
static SensorState sensor_state[STATE_CACHE_CNT];
static int iIndex = 0;
static int oIndex = 0;


struct sensor_irq_desc 
{
	int irq;
	int pin;
	int pin_setting;
	int number;
	char *name;	
};

static struct sensor_irq_desc sensor_irqs [] = {
	{IRQ_EINT0, S3C2410_GPF(0) ,  S3C2410_GPF0_EINT0  , 0, "Sensor0"},
	{IRQ_EINT1, S3C2410_GPF(1) ,  S3C2410_GPF1_EINT1 , 1, "Sensor1"},
	{IRQ_EINT2, S3C2410_GPF(2) ,  S3C2410_GPF2_EINT2 , 2, "Sensor2"},
	{IRQ_EINT3, S3C2410_GPF(3) ,  S3C2410_GPF3_EINT3 , 3, "Sensor3"},
	{IRQ_EINT4, S3C2410_GPF(4) ,  S3C2410_GPF4_EINT4 , 4, "Sensor4"},
	{IRQ_EINT5, S3C2410_GPF(5) ,  S3C2410_GPF5_EINT5 , 5, "Sensor5"},
	{IRQ_EINT8, S3C2410_GPG(0) ,  S3C2410_GPG0_EINT8 , 6, "Sensor6"},
	{IRQ_EINT9, S3C2410_GPG(1) ,  S3C2410_GPG1_EINT9 , 7, "Sensor7"},
	{IRQ_EINT11, S3C2410_GPG(3) ,  S3C2410_GPG3_EINT11 , 8, "Sensor8"},
};

//one bit represent one sensor 1:mask 0:unmask
static int isOpen = 0;





static irqreturn_t sensor_interrupt(int irq, void *dev_id)
{

	struct sensor_irq_desc *sensor_irqs = (struct sensor_irq_desc *)dev_id;
	int state = 0; 

	// udelay(0);
	state = s3c2410_gpio_getpin(sensor_irqs->pin);
//	printk (DEVICE_NAME"\t state = %d\n", state);
	sensor_state[iIndex].id = sensor_irqs->number;
	sensor_state[iIndex].state = state; 
	sensor_state[iIndex].tick = jiffies; 
	iIndex++;
	if(iIndex == STATE_CACHE_CNT)
	{
		iIndex = 0;
	}
	if(iIndex == oIndex)
	{
		
		assert(false);
	}


	return IRQ_RETVAL(IRQ_HANDLED);
}


static int sensor_open(struct inode *inode, struct file *file)
{
	int i;
	int err = 0;

	if(isOpen)
	{
		return -EBUSY;
	}

	for (i = 0; i < sizeof(sensor_irqs)/sizeof(sensor_irqs[0]); i++) 
	{
		if (sensor_irqs[i].irq < 0) 
		{
			continue;
		}
		err = request_irq(sensor_irqs[i].irq, sensor_interrupt, IRQ_TYPE_EDGE_BOTH, 
				sensor_irqs[i].name, (void *)&sensor_irqs[i]);

		printk (DEVICE_NAME"\t..ok\n");
		if (err)
		{

			printk (DEVICE_NAME"\t..fail\n");
			break;
		}
	}

	if (err)
	{
		i--;
		for (; i >= 0; i--) 
		{
			if (sensor_irqs[i].irq < 0) {
				continue;
			}
			disable_irq(sensor_irqs[i].irq);
			free_irq(sensor_irqs[i].irq, (void *)&sensor_irqs[i]);
		}
		return -EBUSY;
	}
	isOpen = 1;


	return 0;
}

static int sensor_fasync(int fd, struct file *filp, int mode)
{

	return fasync_helper(fd, filp, mode, &async_queue);

}



static int sensor_close(struct inode *inode, struct file *file)
{
	int i;

	for (i = 0; i < sizeof(sensor_irqs)/sizeof(sensor_irqs[0]); i++) {
		if (sensor_irqs[i].irq < 0) {
			continue;
		}
		free_irq(sensor_irqs[i].irq, (void *)&sensor_irqs[i]);
	}

	sensor_fasync(-1, file, 0);



	return 0;
}


static int sensor_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
	unsigned long err;
	int cnt = 0;
	int tmpIIndex = iIndex;

	if(tmpIIndex < oIndex)
	{
		cnt = tmpIIndex + STATE_CACHE_CNT - oIndex;
	}
	else
	{
		cnt = tmpIIndex - oIndex;
	}

	if(!buff)
	{
		return cnt;
	}

	if(tmpIIndex < oIndex)
	{

		err = copy_to_user(buff, (const void *)&sensor_state[oIndex],
				sizeof(sensor_state[0]) * (STATE_CACHE_CNT - oIndex)); 
		err = copy_to_user(buff + sizeof(sensor_state[0]) * (STATE_CACHE_CNT - oIndex),
			(const void *)&sensor_state[0], sizeof(sensor_state[0]) * tmpIIndex); 

	}
	else
	{

		err = copy_to_user(buff, (const void *)&sensor_state[oIndex], sizeof(sensor_state[0]) * cnt); 
	}

	oIndex = tmpIIndex;

	return err ? -EFAULT : cnt; 
}




static struct file_operations dev_fops = {
	.owner   =   THIS_MODULE,
	.open    =   sensor_open,
	.release =   sensor_close, 
	.read    =   sensor_read,
	.fasync	 =	 sensor_fasync,
};

static struct miscdevice misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &dev_fops,
};

static int __init dev_init(void)
{
	int ret;

	ret = misc_register(&misc);

	printk (DEVICE_NAME"\tinitialized hj\n");

	return ret;
}

static void __exit dev_exit(void)
{
	misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hjc");
